

    EventDispatcher.implement
    (
        {
            /**
             * @protected
             * @type {Array}
             */
            listeners: null
            
            /**
             * @protected
             * @type {Object}
             */
        ,   target: null
        
            /**
             * 
             * @param {String} type
             * @param {Function} listener
             * @param {Object} scope
             * @return {void}
             */
        ,   addEventListener: function (type, listener, scope) 
            {
                if (false === type in this.listeners) 
                {
                    this.listeners[type]= [new Invoker(listener, scope)];
                    return;
                }
                
                // listeners maintained in reverse order for faster iteration
                this.listeners[type].unshift(new Invoker(listener, scope)); 
            }
            
            /**
             * 
             * @param {String} type
             * @param {Function} listener
             * @param {Object} scope
             */
        ,   hasEventListener: function (type, listener, scope) 
            {
                if (type in this.listeners) 
                {
                    var listeners= this.listeners[type]
                    ,   n= listeners.length
                    ,   listener= new Invoker(listener, scope);
                    
                    while (n--) 
                    {
                        if (listeners[n].equals(listener))
                            return true;
                    }
                }
                
                return false;
            }
            
            /**
             * 
             * @param {String} type
             * @param {Function} listener
             * @param {Object} scope
             */
        ,   removeEventListener: function (type, listener, scope) 
            {
                if (false === type in this.listeners)
                    return;
                    
                var listeners= this.listeners[type]
                ,   instance= new Invoker(listener, scope)
                ,   listener
                ,   n= listeners.length
                
                while (n--) 
                {
                    if (listener.equals(listeners[n])) 
                    {
                        listeners.splice(n, 1);
                        return;
                    }
                }
            }
            
            /**
             * 
             * @param {String} type
             * @return {void}
             */
        ,   removeAllEventListeners: function (type) 
            {
                delete this.listeners[type];
            }
            
            /**
             * 
             * @param {Object} customEvent
             * @return {void}
             */
        ,   dispatchEvent: function (customEvent) 
            {
                var type= customEvent.type
                ,   listeners
                ,   n
                
                if (type in this.events) 
                {
                    customEvent.target= this.target;
                    listeners= this.listeners[type]
                    n= listeners.length;
                    while (--n) 
                    {
                        listeners[n](customEvent);
                    }
                }                     
            }
            
            /**
             * 
             * @param {String} type
             * @return {Boolean}
             */
        ,   willTrigger: function (type) 
            {
                return type in this.listeners;
            }
        }
    );
    
    /**
     * 
     * @param {Object} target
     * @constructor
     */
    function EventDispatcher (target) 
    {
        this.target= target || this;
    };
    
    Invoker.implement
    (
        {
            /**
             * 
             * @type {Object}
             */
            scope: null
            
            /**
             * 
             * @type {Function}
             */
        ,   method: null
        
            /**
             * 
             * @return {Object}
             */
        ,   invoke: function () 
            {
                return this.method.apply(this.scope, arguments);
            }
            
            /**
             * 
             * @param {Object} listener
             * @return {Boolean}
             */
        ,   equals: function (value) 
            {
                if (Invoker.type(value)) 
                {
                    return this.scope === value.scope && this.method === value.method;
                }

                return false;
            }     
        }
    );
    
    /**
     * 
     * @param {Function} method
     * @param {Object} scope
     */
    function Invoker (method, scope) 
    {
        this.method= method;
        this.scope= scope;
    };
    
    
    Function.implement
    (
        function like (value) 
        {
            if (null == value)
                return false;
                
            var prototype= this.prototype
            ,   accessor
    
            for (accessor in prototype) 
            {
                if('function' === typeof prototype[accessor]
                && 'constructor' !== accessor
                && '_' !== accessor.charAt(0)
                && 'function' !== typeof value[accessor])
                    return false;
            }
            
            return true;
        }
    ); 

    
    
    
    Inheritor.inherits(EventDispatcher);
    function Inheritor ()
    {
        EventDispatcher.call(this);
    };
    
    Borrower.implement(EventDispatcher.prototype);
    function Borrower () 
    {
        EventDispatcher.call(this);
    };
    
    
    var inheritor= new Inheritor
    ,   borrower= new Borrower
    

    alert(EventDispatcher.like(inheritor)) // true
    alert(EventDispatcher.like(borrower)) // true
    alert(EventDispatcher.type(inheritor)) // true
    alert(EventDispatcher.type(borrower)) // false
    
    alert(inheritor.parent === EventDispatcher.prototype); // true
    alert(borrower.parent === EventDispatcher.prototype); // false
    
    
    
    
    
    
    
